//==================================================================
//  Copyright (C) 2006-2007  Davide Pasca
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//==================================================================
///
///
///
///
///
//==================================================================

#include <stdio.h>
#include <stdarg.h>
#include <windows.h>
#include <gl/glew.h>
#include "psys.h"
#include "fontuni.h"

#define MAP_WD	2048
#define MAP_HE	128

//==================================================================
FontUni::FontUni( u_int font_size ) :
	_hbmp(NULL),
	_hdc(NULL),
	_datap(NULL),
	_data_outtexp(NULL),
	_hfont(NULL),
	_tx_id(0),
	_font_he(0),
	_tail_he(2)	// $$$ should be properly queried from the font !!!
{
	LOGFONT	lf;

	_hdc = CreateCompatibleDC( GetDC(NULL) );
	memset( &lf, 0, sizeof(lf) );
	//strcpy_s( (LPSTR)&lf.lfFaceName, "MS Gothic" );
	_tcscpy_s( lf.lfFaceName, _T("Lucida Sans Unicode") );
	//lf.lfPitchAndFamily = FF_SWISS;
	lf.lfHeight = -MulDiv( font_size, GetDeviceCaps( _hdc, LOGPIXELSY ), 72 );

	_hfont = CreateFontIndirect( &lf );

	SelectObject( _hdc, _hfont );

	allocOffscreen( 2048, 128 );
	createTexture( 2048, 128 );

	SIZE	sz;
	TCHAR	*teststrp = _T("QWERTYyuitil");
	GetTextExtentPoint32( _hdc, teststrp, _tcslen(teststrp), &sz );

	_font_he = sz.cy;
}

//==================================================================
void FontUni::allocOffscreen( u_int w, u_int h )
{
	_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	_bmi.bmiHeader.biWidth = w;
	_bmi.bmiHeader.biHeight = -(int)h;
	_bmi.bmiHeader.biPlanes = 1;
	_bmi.bmiHeader.biBitCount = 32;
	_bmi.bmiHeader.biCompression = BI_RGB;
	_bmi.bmiHeader.biSizeImage = 0;
	_bmi.bmiHeader.biXPelsPerMeter = 1000;
	_bmi.bmiHeader.biYPelsPerMeter = 1000;
	_bmi.bmiHeader.biClrImportant = 0;
	_bmi.bmiHeader.biClrUsed = 0;

	_hbmp = CreateDIBSection( _hdc, &_bmi,
								 DIB_RGB_COLORS,
								 &_datap,
								 NULL, 0 );

	if ( !_datap )
		throw "ooppsss !";

	SelectObject( _hdc, _hbmp );

	RECT	rc;
	rc.left = 0;
	rc.top = 0;
	rc.right = w;
	rc.bottom = h;
	FillRect( _hdc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH) );

	_data_outtexp = new u_char[ MAP_WD*4 * MAP_HE ];
	memset( _data_outtexp, 0xff, MAP_WD*4 * MAP_HE );
}

//==================================================================
void FontUni::createTexture( u_int w, u_int h )
{
	glGenTextures( 1, &_tx_id );
	glBindTexture( GL_TEXTURE_2D, _tx_id );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
//	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
//	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
	glTexImage2D( GL_TEXTURE_2D,
					0,  //mipmap level
					GL_RGBA8,
					w, h, //size
					0,  //border
					GL_RGBA, //element format
					GL_UNSIGNED_BYTE, //element type (data size)
					NULL );  //pixel data
}

//==================================================================
void FontUni::puts( const TCHAR *strp )
{
	SIZE	sz;
	size_t	len = _tcslen(strp);
	GetTextExtentPoint32( _hdc, strp, len, &sz );
	SetTextColor( _hdc, RGB(255,255,255) );
	SetBkColor( _hdc, RGB(0,0,0) );
	TextOut( _hdc, 0, 0, strp, len );

	if ( sz.cx > 2048 )
		sz.cx = 2048;
	
	if ( sz.cy > 128 )
		sz.cy = 128;

	//memset( _datap, 0xff, 2048*128 * 3 );
	const u_char	*srcp = (const u_char *)_datap;
	u_char			*desp = (u_char *)_data_outtexp;
	for (int y = 0; y < sz.cy; ++y)
	{
		const u_char	*srcp2 = srcp;
		srcp += MAP_WD * 4;

		for (int x = sz.cx; x; --x)
		{
			desp[3] = srcp2[1];
			srcp2 += 4;
			desp += 4;
		}
	}

	glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, sz.cx, sz.cy,
					 GL_RGBA, GL_UNSIGNED_BYTE, _data_outtexp );

	float	tx1 = 0;
	float	ty1 = 0;
	float	tx2 = sz.cx / 2048.0f;
	float	ty2 = sz.cy / 128.0f;

	glBegin( GL_QUADS );
		glTexCoord2f( tx1, ty1 );		glVertex2f( 0, 0 );
		glTexCoord2f( tx2, ty1 );		glVertex2f( sz.cx, 0 );
		glTexCoord2f( tx2, ty2 );		glVertex2f( sz.cx, sz.cy );
		glTexCoord2f( tx1, ty2 );		glVertex2f( 0, sz.cy );
	glEnd();
}

//==================================================================
void FontUni::vprintf( const TCHAR *strp, va_list valist )
{
	TCHAR	buff[4096];

	_vstprintf_s( buff, strp, valist );
	FontUni::puts( buff );
}

//==================================================================
void FontUni::printf( const TCHAR *strp, ... )
{
	va_list	va;

	va_start( va, strp );
		FontUni::vprintf( strp, va );
	va_end( va );
}

//==================================================================
int FontUni::TextHeight()
{
	return _font_he;
}

//==================================================================
int FontUni::StringWidth( const TCHAR *strp )
{
	SIZE	sz;

	GetTextExtentPoint32( _hdc, strp, _tcslen(strp), &sz );

	return sz.cx;
}
/*
//==================================================================
void FontUni::BoxAlignPF( int align_x, int align_y, const PSYS::RectF &in_rect,
						  int *out_xp, int *out_yp, const TCHAR *strp, ... )
{
	*out_yp = calc_y( in_rect._y, in_rect._h, align_y );

	if ( align_x < 0 )
	{
		*out_xp = in_rect._x;									// left
	}
	else
	{
		TCHAR	buff[4096];
		int		len, swd;
		va_list	va;

		va_start( va, strp );
			if ( (len = _vstprintf_s( buff, strp, va )) > 0 )
			{
				swd = FontUni::StringWidth( buff );
			}
			PASSERT( len >= 0 );
		va_end( va );

		if ( align_x > 0 )
			*out_xp = in_rect._x + in_rect._w - swd;			// right
		else
			*out_xp = in_rect._x + (in_rect._w - swd) / 2;		// center
	}
}
*/
//==================================================================
int FontUni::calc_y( int y0, int h, int align_y )
{
	if ( align_y < 0 )
		return y0 - _tail_he;						// top
	else
	if ( align_y > 0 )
		return y0 + h - _font_he - _tail_he;			// bottom
	else
		return y0 + (h - _font_he) / 2 - _tail_he;	// middle
}

//==================================================================
void FontUni::puts_pos_ba( const PSYS::RectF &in_rect, int align_x, int align_y, const TCHAR *strp )
{
int	x, y, swd;

	y = calc_y( in_rect._y, in_rect._h, align_y );

	if ( align_x < 0 )
	{
		x = in_rect._x;									// left
	}
	else
	{
		swd = FontUni::StringWidth( strp );

		if ( align_x > 0 )
			x = in_rect._x + in_rect._w - swd;			// right
		else
			x = in_rect._x + (in_rect._w - swd) / 2;	// center
	}

	glPushMatrix();
		glTranslatef( x, y, 0 );
		puts( strp );
	glPopMatrix();
}

//==================================================================
void FontUni::printf_pos_ba( const PSYS::RectF &in_rect, int align_x, int align_y, const TCHAR *strp, ... )
{
	TCHAR	buff[4096];
	int		len;
	va_list	va;

	va_start( va, strp );

		if ( (len = _vstprintf_s( buff, strp, va )) > 0 )
		{
			buff[ _countof(buff)-1 ] = 0;
			FontUni::puts_pos_ba( in_rect, align_x, align_y, buff );
		}
		PASSERT( len >= 0 );

	va_end( va );
}

//==================================================================
void FontUni::DrawBegin()
{
	glPushAttrib( GL_ENABLE_BIT | GL_TEXTURE_BIT ); 

	glEnable( GL_TEXTURE_2D );
	glBindTexture( GL_TEXTURE_2D, _tx_id );

	glMatrixMode( GL_TEXTURE );
	glLoadIdentity();

	glMatrixMode( GL_MODELVIEW );
	glEnable( GL_BLEND );
	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}

//==================================================================
void FontUni::DrawEnd()
{
	glPopAttrib();
}
